package cn.iocoder.yudao.module.lfd.pay;

import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.lfd.controller.admin.appointment.vo.AppointmentEnum;
import cn.iocoder.yudao.module.lfd.controller.admin.appointment.vo.PayTypeEnum;
import cn.iocoder.yudao.module.lfd.controller.admin.order.vo.OrderPageReqVO;
import cn.iocoder.yudao.module.lfd.dal.dataobject.appointment.AppointmentDO;
import cn.iocoder.yudao.module.lfd.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.lfd.service.appointment.AppointmentService;
import cn.iocoder.yudao.module.lfd.service.order.OrderService;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;

@Component
@Slf4j
public class PayOrderService {
    @Autowired
    private AppointmentService appointmentService;
    @Autowired
    private OrderService orderService;

    @Autowired
    private WxPayService wxService;


    @Transactional
    public Object unifiedOrder(Long id) throws Exception {
        AppointmentDO appointment = appointmentService.getAppointment(id);
        String flowNo = IdUtil.getSnowflake().nextIdStr();
        Object orderV3 = wxOrder(appointment, flowNo);
        orderService.createOrder(appointment.getId(), flowNo);
        return orderV3;
    }

    private Object wxOrder(AppointmentDO appointment, String flowNo) throws WxPayException {
        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        request.setDescription("餐饮消费");
        request.setOutTradeNo(flowNo);
        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount().setTotal(appointment.toFen());
        request.setAmount(amount);
        //5分钟失效
        request.setTimeExpire(TemporalAccessorUtil.format(LocalDateTimeUtils.addTime(Duration.ofSeconds(300))
                .atZone(ZoneId.systemDefault()), "yyyy-MM-dd'T'HH:mm:ssXXX"));
        request.setNotifyUrl(wxService.getConfig().getNotifyUrl());
        request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(appointment.getOpenid()));
        request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp("127.0.0.1"));
        return wxService.createOrderV3(TradeTypeEnum.JSAPI, request);
    }


    public void success(String status, String outTradeNo) {
        OrderDO order = orderService.getOrder(outTradeNo);
        if ("SUCCESS".equals(status)) {
            appointmentService.finish(PayTypeEnum.WX,order.getAppointmentId(),outTradeNo);
            orderService.updateOrder(order.success());
        } else {
            orderService.updateOrder(order.fail());
        }
    }


    @Scheduled(cron = "0 */1 * * * ?")
    public void handlePayingOrder() {
        OrderPageReqVO orderPageReqVO = new OrderPageReqVO();
        orderPageReqVO.setPageSize(30);
        orderPageReqVO.setStatus(AppointmentEnum.PAYING);
        LocalDateTime time[] = {LocalDateTime.now().plusHours(-12), LocalDateTime.now().plusMinutes(-6)};
        orderPageReqVO.setCreateTime(time);
        PageResult<OrderDO> orderPage = orderService.getOrderPage(orderPageReqVO);
        for (OrderDO orderDO : orderPage.getList()) {
            try {
                WxPayOrderQueryV3Result results = wxService.queryOrderV3(null, orderDO.getId());
                success(results.getTradeState(), results.getOutTradeNo());
            } catch (Exception e) {
                log.error("定时任务查询订单失败",e);
            }
        }
    }
}
